﻿
Imports System.IO
Imports System.Net
Imports osi.root.procedure
Imports osi.root.utils
Imports osi.root.formation
Imports osi.root.connector

Public Class http_responder
    Public Shared ReadOnly [default] As http_responder
    Public ReadOnly read_request_body_as_string As binder(Of Func(Of HttpListenerContext, 
                                                                     pointer(Of String), 
                                                                     event_comb), 
                                                             http_responder)
    Private ReadOnly dispatcher As dispatcher

    Shared Sub New()
        [default] = New http_responder(commander.dispatcher.default)
    End Sub

    Public Sub New(ByVal dispatcher As dispatcher)
        assert(Not dispatcher Is Nothing)
        Me.dispatcher = dispatcher
        Me.read_request_body_as_string = New binder(Of Func(Of HttpListenerContext, 
                                                               pointer(Of String), 
                                                               event_comb), 
                                                       http_responder)()
    End Sub

    Private Function handle(ByVal i As String, ByVal o As pointer(Of String)) As event_comb
        Dim ic As command = Nothing
        Dim oc As command = Nothing
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  ic = New command()
                                  If Not ic.from_uri(i) Then
                                      Return False
                                  Else
                                      oc = New command()
                                      ec = dispatcher.dispatch(ic, oc)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  End If
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         eva(o, oc.to_uri()) AndAlso
                                         goto_end()
                              End Function)
    End Function

    Private Function handle_as_post(ByVal ctx As HttpListenerContext, ByVal o As pointer(Of String)) As event_comb
        assert(Not ctx Is Nothing)
        Dim i As pointer(Of String) = Nothing
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If read_request_body_as_string.has_value() Then
                                      i = New pointer(Of String)()
                                      ec = (+read_request_body_as_string)(ctx, i)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  Else
                                      Return False
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec.end_result() Then
                                      ec = handle(+i, o)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  Else
                                      Return False
                                  End If
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         goto_end()
                              End Function)
    End Function

    Private Function handle(ByVal ctx As HttpListenerContext, ByVal o As pointer(Of String)) As event_comb
        assert(Not ctx Is Nothing)
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If ctx.Request().HasEntityBody() Then
                                      ec = handle_as_post(ctx, o)
                                  Else
                                      ec = handle(ctx.Request().Url().AbsolutePath(), o)
                                  End If
                                  Return waitfor(ec) AndAlso
                                         goto_next()
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         goto_end()
                              End Function)
    End Function

    Public Sub handler(ByVal ctx As HttpListenerContext, ByRef ec As event_comb)
        assert(Not ctx Is Nothing)
        Dim iec As event_comb = Nothing
        Dim o As pointer(Of String) = Nothing
        ec = New event_comb(Function() As Boolean
                                o = New pointer(Of String)()
                                iec = handle(ctx, o)
                                Return waitfor(iec) AndAlso
                                       goto_next()
                            End Function,
                            Function() As Boolean
                                If iec.end_result() AndAlso Not String.IsNullOrEmpty(+o) Then
                                    Dim buff() As Byte = Nothing
                                    buff = str_bytes(+o)
                                    ctx.Response().StatusCode() = HttpStatusCode.OK
                                    ctx.Response().StatusDescription() = "OK"
                                    ctx.Response().ContentLength64() = array_size(buff)
                                    ctx.Response().ContentType() = strcat(constants.http_responder_content_type,
                                                                          root.constants.content_type_charset_prefix,
                                                                          default_encoding.WebName())
                                    Return waitfor(ctx.Response().OutputStream().write(buff)) AndAlso
                                           goto_end()
                                Else
                                    ctx.Response().StatusCode() = HttpStatusCode.BadRequest
                                    ctx.Response().StatusDescription() = "CANNOT_FULFILL_REQUEST"
                                    Return goto_end()
                                End If
                            End Function)
    End Sub
End Class
